home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch06 / ufo.c < prev    next >
C/C++ Source or Header  |  1994-07-22  |  37KB  |  1,047 lines

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<conio.h>
  4. #include<fcntl.h>
  5. #include<io.h>
  6. #include<math.h>
  7. #include<vsa.h>
  8. #include<vsa_font.h>
  9. #include <sys\types.h>
  10. #include<sys\stat.h>
  11.  
  12. #ifndef _MSC_VER
  13. /*.....             This is for Borland C Only !          .....*/
  14. extern unsigned _stklen = 10000;
  15. #endif
  16.  
  17. #define FAST_RGB 0  /* Set to 1 for fast, lower quality images */
  18.  
  19. /*.............................................................*/
  20. /*                 Function Prototypes go here.                */
  21. /*.............................................................*/
  22. void        introduction(void);
  23. void      azure_sky(unsigned char *,int,int);
  24. void      wipe_sky(unsigned char *,int,int);
  25. void      shrink_city(unsigned char *,int,int);
  26. void      merge_city(unsigned char *,int,int);
  27. void      merge_azure(unsigned char *,unsigned char *,int,int);
  28. void      shrink_saucer(unsigned char *,int,int);
  29. void      merge_saucer(unsigned char *,int,int);
  30. void      add_shadow(unsigned char *,int,int);
  31. void      add_beam(unsigned char *,int,int);
  32. void      get_dithered_row(int,int,unsigned char *,
  33.                                                      unsigned char *);
  34. int       crack_rgb(unsigned char *,int *,int *,int *,float *,
  35.                                         float *,float *);
  36. long      read_tga_header(int,int *,int *,int *,int *);
  37. int       write_tga_header(int,int,int,int);
  38. void      true_color_lut(void);
  39. void      process_step(unsigned char *,unsigned char *,
  40.                                              int,int,int);
  41. float     color_mag(float,float,float);
  42. float     color_error(float,float,float,float,float,float);
  43. float     hue_error(float,float,float,float,float,float);
  44. void      bummer(char *);
  45. void      text_update(char *,int);
  46. void      frame(void);
  47. void      ellipse(int,int);
  48. void             soft_edge(unsigned char *,int,int);
  49.  
  50.  
  51. /*.............................................................*/
  52. /*            External Parameters declared here.               */
  53. /*.............................................................*/
  54. unsigned char dither[4][64]={
  55. {
  56.  1 },
  57. {
  58.  1, 3,
  59.  4, 2 },
  60. {
  61.  1,  9, 3, 11,
  62. 13,  5, 15, 7,
  63.  4, 12, 2, 10,
  64. 16,  8, 14, 6 },
  65. {
  66.  1, 33,  9, 41,  3, 35, 11, 43,
  67. 49, 17, 57, 25, 51, 19, 59, 27,
  68. 13, 45,  5, 37, 15, 47,  7, 39,
  69. 61, 29, 53, 21, 63, 31, 55, 23,
  70.  4, 36, 12, 44,  2, 34, 10, 42,
  71. 52, 20, 60, 28, 50, 18, 58, 26,
  72. 16, 48,  8, 40, 14, 46,  6, 38,
  73. 64, 32, 56, 24, 62, 30, 54, 22 },
  74. };
  75.  
  76. char file_i1[9][30]={
  77. {""},
  78. {"mountain.tga"},
  79. {"city.tga"},
  80. {"wiped.tga"},
  81. {"withcity.tga"},
  82. {"saucer.tga"},
  83. {"withsky.tga"},
  84. {"withsauc.tga"},
  85. {"withshad.tga"},
  86. };
  87.  
  88. char file_i2[9][30]={
  89. {""},
  90. {""},
  91. {""},
  92. {""},
  93. {"sky.tga"},
  94. {""},
  95. {""},
  96. {""},
  97. {""},
  98. };
  99.  
  100. char file_o[9][30]={
  101. {"sky.tga"},
  102. {"wiped.tga"},
  103. {""},
  104. {"withcity.tga"},
  105. {"withsky.tga"},
  106. {""},
  107. {"withsauc.tga"},
  108. {"withshad.tga"},
  109. {"ufo.tga"},
  110. };
  111.  
  112. unsigned char far image[16384];
  113. unsigned far big_image[16384];
  114.  
  115. void main()
  116. {
  117.     int j,width,height,type,orient;
  118.     int file_i1_handle,file_i2_handle,file_o_handle;
  119.     int jstrt,jend,jstep,step;
  120.     unsigned char rgb_1[3072],rgb_2[3072];
  121.     char text[100];
  122.     width = 640;
  123.     height = 480;
  124.     orient = 0;
  125.     introduction();
  126. /*.............................................................*/
  127. /*            Set highest video resolution available.          */
  128. /*.............................................................*/
  129.             if(vsa_init(0x101) != 0)            /*  640 x 480 x 256 */
  130.                 if(vsa_init(0x100) != 0)          /*  640 x 400 x 256 */
  131.                     {
  132.                         printf("Can't set VESA video mode\n");
  133.                         printf("Is VESA BIOS Extension TSR loaded?\n");
  134.                         return;
  135.                     }
  136.     true_color_lut();
  137.     for(step=0;step<9;step++)
  138.         {
  139. /*.............................................................*/
  140. /*  Open the TARGA file(s) and get header info.  When two files*/
  141. /*  being opened simultaneously, they must be same type, size, */
  142. /*  and orientation!                                           */
  143. /*.............................................................*/
  144.             if(file_i1[step][0])
  145.                 {
  146.                     if((file_i1_handle = open(file_i1[step],
  147.                             O_BINARY | O_RDONLY)) == -1)
  148.                         bummer(file_i1[step]);
  149.                     else
  150.                         if(read_tga_header(file_i1_handle,&width,
  151.                                                         &height,&type,&orient) == -1)
  152.                             bummer(file_i1[step]);
  153.                 }
  154.             if(file_i2[step][0])
  155.                 {
  156.                     if((file_i2_handle = open(file_i2[step],
  157.                             O_BINARY | O_RDONLY)) == -1)
  158.                         bummer(file_i2[step]);
  159.                     else
  160.                         if(read_tga_header(file_i2_handle,&width,
  161.                                                         &height,&type,&orient) == -1)
  162.                             bummer(file_i2[step]);
  163.                 }
  164.             if(file_o[step][0])
  165.                 {
  166.                     if((file_o_handle = open(file_o[step],
  167.                             O_BINARY | O_WRONLY | O_CREAT | O_TRUNC,
  168.                             S_IWRITE | S_IREAD)) == -1)
  169.                         bummer(file_o[step]);
  170.                     else
  171.                         if(write_tga_header(file_o_handle,width,
  172.                                                          height,orient) == -1)
  173.                             bummer(file_o[step]);
  174.                 }
  175. /*.............................................................*/
  176. /*              Prepare to read out TARGA file(s).             */
  177. /*.............................................................*/
  178.             if(orient == 32)
  179.                 {
  180.                     jstrt = 0;
  181.                     jend = height;
  182.                     jstep = 1;
  183.                 }
  184.             else
  185.                 {
  186.                     jstrt = height-1;
  187.                     jend = -1;
  188.                     jstep = -1;
  189.                 }
  190. /*.............................................................*/
  191. /*    Do a Quicky Display of the TARGA file in file_i1,        */
  192. /*    (And remember to reset file pointer !!!)                 */
  193. /*    Only do this where it makes sense (steps 1, 2, and 5).   */
  194. /*.............................................................*/
  195.             if((step == 1) || (step == 2) || (step == 5))
  196.                 {
  197.                     frame();
  198.                     if(file_i1[step][0])
  199.                         {
  200.                          text_update("Displaying the Input File.",252);
  201.                          for(j=jstrt;j!=jend;j+=jstep)
  202.                             {
  203.                                 if(read(file_i1_handle,rgb_1,3*width) != 3*width)
  204.                                         bummer(file_i1[step]);
  205.                                 get_dithered_row(width,j,rgb_1,rgb_2);
  206.                                 vsa_raster_line(0,width-1,j,rgb_2);
  207.                             }
  208.                          lseek(file_i1_handle,18,SEEK_SET);
  209.                         }
  210.                 }
  211. /*.............................................................*/
  212. /*    Read out pixels from TARGA file(s) and process them.     */
  213. /*.............................................................*/
  214.             text_update("Processing, Please Wait.",252);
  215.             frame();
  216.             for(j=jstrt;j!=jend;j+=jstep)
  217.                 {
  218.                     if(file_i1[step][0])
  219.                         if(read(file_i1_handle,rgb_1,3*width) != 3*width)
  220.                             bummer(file_i1[step]);
  221.                     if(file_i2[step][0])
  222.                         if(read(file_i2_handle,rgb_2,3*width) != 3*width)
  223.                             bummer(file_i2[step]);
  224.                     process_step(rgb_1,rgb_2,width,j,step);
  225.                     if(file_o[step][0])
  226.                         if(write(file_o_handle,rgb_1,3*width) != 3*width)
  227.                             bummer(file_o[step]);
  228.                 }
  229. /*.............................................................*/
  230. /*           If a file was opened, close it now.               */
  231. /*.............................................................*/
  232.             if(file_i1[step][0]) close(file_i1_handle);
  233.             if(file_i2[step][0]) close(file_i2_handle);
  234.             if( file_o[step][0])  close(file_o_handle);
  235. /*.............................................................*/
  236. /*  Here's your chance too get out ...                         */
  237. /*.............................................................*/
  238.             sprintf(text,"Step %d Done.  Hit Any Key.",step);
  239.             text_update(text,224);
  240.             if(getch() == 27)
  241.                 goto BAIL;
  242.             frame();
  243.         }
  244. /*.............................................................*/
  245. /*   Program is over, return display to standard text mode.    */
  246. /*.............................................................*/
  247. BAIL:
  248.     vsa_init(0x3);
  249.     return;
  250. }
  251.  
  252. void process_step(unsigned char *rgb_1,unsigned char *rgb_2,
  253.                                     int width,int j,int step)
  254. {
  255.     switch(step)
  256.         {
  257.             case 0:
  258.                                 azure_sky(rgb_1,width,j);
  259.                                 break;
  260.             case 1:
  261.                                 wipe_sky(rgb_1,width,j);
  262.                                 break;
  263.             case 2:
  264.                                 shrink_city(rgb_1,width,j);
  265.                                 break;
  266.             case 3:
  267.                                 merge_city(rgb_1,width,j);
  268.                                 break;
  269.             case 4:
  270.                                 merge_azure(rgb_1,rgb_2,width,j);
  271.                                 break;
  272.             case 5:
  273.                                 shrink_saucer(rgb_1,width,j);
  274.                                 break;
  275.             case 6:
  276.                                 merge_saucer(rgb_1,width,j);
  277.                                 break;
  278.             case 7:
  279.                                 add_shadow(rgb_1,width,j);
  280.                                 break;
  281.             case 8:
  282.                                 add_beam(rgb_1,width,j);
  283.                                 break;
  284.             default:  break;
  285.         }
  286.     return;
  287. }                         /*.... END process_step         .....*/
  288.  
  289.  
  290. /*........................ AZURE_SKY ..........................*/
  291. /*  This routine generates a blue, blue-green gradient much    */
  292. /*  like the crisp blue skies of Montana. (Never been there,   */
  293. /*  seen pictures). (The data is displayed as its generated).  */
  294. /*.............................................................*/
  295. void azure_sky(unsigned char *rgb_1,int width,int j)
  296. {
  297.     unsigned char array[1024];
  298.     int i;
  299.     for(i=0;i<width;i++)
  300.         {
  301.             rgb_1[3*i+2] = 0;
  302.             rgb_1[3*i+1] = 64+j/2.53;
  303.             rgb_1[3*i+0] = 128+j/3.75;
  304.         }
  305.     get_dithered_row(width,j,rgb_1,array);
  306.     vsa_raster_line(0,width-1,j,array);
  307.     return;
  308. }                         /*.... END azure_sky            .....*/
  309.  
  310.  
  311. /*......................... WIPE_SKY ..........................*/
  312. /*  This routine is customized to work specifically with the   */
  313. /*  MOUNTAIN.TGA picture.  It goes in and zeros out the sky to */
  314. /*  prepare MOUNTAIN.TGA for the next step.                    */
  315. /*    This routine makes use of a hue test and a color test    */
  316. /*  to determine which pixels make up the sky.  The hue test   */
  317. /*  finds similar hues independent of brightness while the     */
  318. /*  color test finds similar colors in the absolute sense.     */
  319. /*.............................................................*/
  320. void wipe_sky(unsigned char *rgb_1,int width,int j)
  321. {
  322.     unsigned char array[1024];
  323.     int i;
  324.     float h_error,c_error;
  325.     for(i=0;i<width;i++)
  326.         {
  327.                 h_error = hue_error(rgb_1[3*i+2],rgb_1[3*i+1],
  328.                                                         rgb_1[3*i+0],0.62,0.54,0.58);
  329.                 c_error = color_error(rgb_1[3*i+2],rgb_1[3*i+1],
  330.                                                             rgb_1[3*i+0],140,122,131);
  331.                 if((h_error < 0.03) && (c_error < 17))
  332.                 {
  333.                     rgb_1[3*i+2] = 0;
  334.                     rgb_1[3*i+1] = 0;
  335.                     rgb_1[3*i+0] = 0;
  336.                 }
  337.         }
  338.     get_dithered_row(width,j,rgb_1,array);
  339.     vsa_raster_line(0,width-1,j,array);
  340.     return;
  341. }                         /*.... END wipe_sky             .....*/
  342.  
  343.  
  344. /*......................... SHRINK_CITY .......................*/
  345. /*  This routine is customized to work specifically with the   */
  346. /*  CITY.TGA picture.  It extracts the city within a window    */
  347. /*  and shrinks it by a factor of 3 in x and y.  Then the      */
  348. /*  resulting image is placed in the external 'image' array    */
  349. /*  and also displayed on the screen.                          */
  350. /*.............................................................*/
  351. void shrink_city(unsigned char *rgb_1,int width,int j)
  352. {
  353.     int i,n,q,red,grn,blu;
  354.     unsigned char array[1024];
  355. /*.............................................................*/
  356. /*  Put up a gray box where reduced city will be drawn.        */
  357. /*  Only draw it once, just before city shrinking starts.      */
  358. /*.............................................................*/
  359.     if(j == 479)
  360.         {
  361.             vsa_set_color(0x49);
  362.             vsa_move_to(242,331);
  363.             vsa_rect_fill(356,406);
  364.         }
  365. /*.............................................................*/
  366. /*  Bail out unless you're within the extract region of the    */
  367. /*  image and you're on every 3rd row.                         */
  368. /*.............................................................*/
  369.     if((j < 60) || (j > 290))
  370.         return;
  371.     if((((float)j/3.0)-j/3) != 0)
  372.         return;
  373. /*.............................................................*/
  374. /*  Extract city within rectangle 115,60 to 460,290 and reduce */
  375. /*  size by a factor of 3 by simple undersampling of image and */
  376. /*  convert extracted pixels to grayscale. Store in image array*/
  377. /*  Then display reduced city in little window.                */
  378. /*.............................................................*/
  379.     n = ((j-60)/3)*115;
  380.     q=j/3+310;
  381.     for(i=115;i<460;i+=3)
  382.         {
  383.             red = rgb_1[3*i+2];
  384.             grn = rgb_1[3*i+1];
  385.             blu = rgb_1[3*i+0];
  386.             image[n] = (red + grn + blu)/3;
  387.             rgb_1[i+2] = image[n];
  388.             rgb_1[i+1] = image[n];
  389.             rgb_1[i+0] = image[n];
  390.             n++;
  391.         }
  392.     get_dithered_row(width,q,rgb_1+115,array);
  393.     vsa_raster_line(242,356,q,array);
  394.     return;
  395. }                         /*.... END shrink_city         .....*/
  396.  
  397. /*.......................... MERGE_CITY .......................*/
  398. /*  This routine takes the reduced city in the 'image' array   */
  399. /*  and inserts it into the WIPED.TGA image replacing only     */
  400. /*  those pixels which are equal to zero.                      */
  401. /*.............................................................*/
  402. void merge_city(unsigned char *rgb_1,int width,int j)
  403. {
  404.     int i,n;
  405.     unsigned char array[1024];
  406. /*.............................................................*/
  407. /*  Composite the city in the 'image' array with the WIPED     */
  408. /*  mountain scene within rectangle (523,214) to (637,289).    */
  409. /*  Also display results.                                      */
  410. /*.............................................................*/
  411.     for(i=0;i<width-1;i++)
  412.         {
  413.             if((j >= 214) && (j <= 289))
  414.                 if((i>=523) && (i < 637))
  415.                     if((rgb_1[3*i+2] | rgb_1[3*i+1] | rgb_1[3*i+0]) == 0)
  416.                         {
  417.                             n=i-523 + (j-214)*115;
  418.                             rgb_1[3*i+2] = image[n];
  419.                             rgb_1[3*i+1] = image[n];
  420.                             rgb_1[3*i+0] = image[n];
  421.                         }
  422.         }
  423.     get_dithered_row(width,j,rgb_1,array);
  424.     vsa_raster_line(0,width-1,j,array);
  425.     return;
  426. }                         /*.... END merge_city          .....*/
  427.  
  428.  
  429. /*.......................... MERGE_AZURE ......................*/
  430. /*  This routine takes the azure sky in SKY.TGA and uses its   */
  431. /*  data to replace all zero value pixels in the previous      */
  432. /*  image WITHCITY.TGA.                                        */
  433. /*.............................................................*/
  434. void merge_azure(unsigned char *rgb_1,unsigned char *rgb_2,
  435.                                  int width,int j)
  436. {
  437.     unsigned char array[1024];
  438.     int i;
  439.     for(i=0;i<width;i++)
  440.         {
  441.             if((rgb_1[3*i+2] | rgb_1[3*i+1] | rgb_1[3*i+0]) == 0)
  442.                 {
  443.                     rgb_1[3*i+2] = rgb_2[3*i+2];
  444.                     rgb_1[3*i+1] = rgb_2[3*i+1];
  445.                     rgb_1[3*i+0] = rgb_2[3*i+0];
  446.                 }
  447.         }
  448.     get_dithered_row(width,j,rgb_1,array);
  449.     vsa_raster_line(0,width-1,j,array);
  450.     return;
  451. }                         /*.... END merge_azure          .....*/
  452.  
  453.  
  454. /*......................... SHRINK_SAUCER .....................*/
  455. /*  This routine is customized to work specifically with the   */
  456. /*  SAUCER.TGA picture.  It extracts the saucer within a window*/
  457. /*  and shrinks it by a factor of 2.5 in x and y.  Then the    */
  458. /*  resulting image is placed in the external 'image' array    */
  459. /*  and also displayed on the screen.                          */
  460. /*.............................................................*/
  461. void shrink_saucer(unsigned char *rgb_1,int width,int j)
  462. {
  463.     int i,n,p,q,red,grn,blu;
  464.     float x;
  465.     unsigned char array[1024];
  466. /*.............................................................*/
  467. /*  Put up a gray box where reduced saucer will be drawn.      */
  468. /*  Only draw it once, just before saucer shrinking starts.    */
  469. /*.............................................................*/
  470.     if(j == 479)
  471.         {
  472.             vsa_set_color(0x49);
  473.             vsa_move_to(235,310);
  474.             vsa_rect_fill(414,379);
  475.         }
  476. /*.............................................................*/
  477. /*  Bail out unless you're within the extract region of the    */
  478. /*  image and you're on every 2.5th row.                       */
  479. /*.............................................................*/
  480.     if((j < 125) || (j > 298))
  481.         return;
  482.     if((int)(j/2.5) == (int)((j-1)/2.5))
  483.         return;
  484. /*.............................................................*/
  485. /*  Extract saucer within rectangle 100,125 to 550,300 and     */
  486. /*  reduce size by a factor of 2.5 by simple undersampling of  */
  487. /*  image and convert extracted pixels to grayscale. Store in  */
  488. /*  'image' array and also dither and display on screen.       */
  489. /*.............................................................*/
  490.     n=180*(int)((j-125)/2.5);
  491.     p=0;
  492.     q=j/2.5+260;
  493.     for(x=100;x<550;x+=2.5)
  494.         {
  495.             i = x+0.5;
  496.             red = rgb_1[3*i+2];
  497.             grn = rgb_1[3*i+1];
  498.             blu = rgb_1[3*i+0];
  499.             image[n] = (red + grn + blu)/3;
  500.             rgb_1[p+2] = image[n];
  501.             rgb_1[p+1] = image[n];
  502.             rgb_1[p+0] = image[n];
  503.             n++;
  504.             p+=3;
  505.         }
  506.     get_dithered_row(width,q,rgb_1,array);
  507.     vsa_raster_line(235,414,q,array);
  508.     return;
  509. }                         /*.... END shrink_saucer        .....*/
  510.  
  511.  
  512. /*.......................... MERGE_SAUCER .....................*/
  513. /*  This routine takes the reduced saucer in the 'image' array */
  514. /*  and inserts it into the WITHSKY.TGA image.  The replacement*/
  515. /*  decision is based on a test of the pixel's blue component  */
  516. /*  in the WITHSKY.TGA picture.                                */
  517. /*.............................................................*/
  518. void merge_saucer(unsigned char *rgb_1,int width,int j)
  519. {
  520.     int i,n;
  521.     unsigned char array[1024];
  522. /*.............................................................*/
  523. /*  Composite the saucer in the image array with the modified  */
  524. /*  mountain scene within the rectangle defined by (203,25)    */
  525. /*  and (382,94).  Use a modified "replace if brighter" test.  */
  526. /*  Specifically, replace if saucer pixel is greater than 1/3  */
  527. /*  of existing pixels blue component.  (nothing magical here, */
  528. /*  this scheme was found by experimenting).                   */
  529. /*.............................................................*/
  530.     n = (j-25)*180;
  531.     for(i=0;i<width-1;i++)
  532.         {
  533.             if((j >= 25) && (j <=  94))
  534.                 if((i >= 203) && (i <= 382))
  535.                     {
  536.                         if(image[n] >= (rgb_1[3*i+0]/3))
  537.                             {
  538.                                 rgb_1[3*i+2] = image[n];
  539.                                 rgb_1[3*i+1] = image[n];
  540.                                 rgb_1[3*i+0] = image[n];
  541.                             }
  542.                         n++;
  543.                     }
  544.         }
  545.     get_dithered_row(width,j,rgb_1,array);
  546.     vsa_raster_line(0,width-1,j,array);
  547.     return;
  548. }                         /*.... END merge_saucer         .....*/
  549.  
  550.  
  551. /*........................ ADD_SHADOW .........................*/
  552. /*  This routine generates an ellipse and then composits it    */
  553. /*  with the WITHSAUC.TGA picture using a subtractive          */
  554. /*  technique.  The ellipse serves as a mask which causes a    */
  555. /*  30% reduction of pixel intensity for masked pixels.        */
  556. /*.............................................................*/
  557. void add_shadow(unsigned char *rgb_1,int width,int j)
  558. {
  559.     int i,n;
  560.     unsigned char array[1024];
  561.     float scale;
  562. /*.............................................................*/
  563. /*  Generate an ellipse mask in the 'image' array once before  */
  564. /*  getting to overlay region.                                 */
  565. /*.............................................................*/
  566.     if(j==479)
  567.         ellipse(180,35);
  568. /*.............................................................*/
  569. /*  Composite the shadow disk region (75,310) (254,344).       */
  570. /*.............................................................*/
  571.     n = (j-310)*180;
  572.     for(i=0;i<width-1;i++)
  573.         {
  574.             if((j >= 310) && (j <= 344))
  575.                 if((i >= 75) && (i <= 254))
  576.                     {
  577.                         scale = (255.0 - 0.4*image[n])/255.0;
  578.                         rgb_1[3*i+2] = rgb_1[3*i+2]*scale;
  579.                         rgb_1[3*i+1] = rgb_1[3*i+1]*scale;
  580.                         rgb_1[3*i+0] = rgb_1[3*i+0]*scale;
  581.                         n++;
  582.                     }
  583.         }
  584.     get_dithered_row(width,j,rgb_1,array);
  585.     vsa_raster_line(0,width-1,j,array);
  586.     return;
  587. }                         /*.... END add_shadow           .....*/
  588.  
  589.  
  590. /*........................ ADD_BEAM ...........................*/
  591. /*  This routine generates a Transporter Beam (the standard    */
  592. /*  issue) and composits it with the WITHSHAD.TGA picture      */
  593. /*  using an additive technique.  The beam has a sinusoidal    */
  594. /*  intensity cross section and is capped with an ellipse.     */
  595. /*.............................................................*/
  596. void add_beam(unsigned char *rgb_1,int width,int j)
  597. {
  598.     int i,n,red,grn,boost;
  599.     unsigned char array[1024];
  600.     float taps[40];
  601. /*.............................................................*/
  602. /*  Generate an ellipse mask in the 'image' array once before  */
  603. /*  getting to overlay region.  Also precompute the            */
  604. /*  sinusoidal beam profile.                                   */
  605. /*.............................................................*/
  606.     if(j==479)
  607.         {
  608.             ellipse(40,22);
  609.             for(i=0;i<40;i++)
  610.                 taps[i] = sin(0.0785*(float)i);
  611.         }
  612. /*.............................................................*/
  613. /*  Use an additive mixing technique to composite the beam     */
  614. /*  (me up scotty) into the image.  Beam fills rectangle with  */
  615. /*  coordinates (273,88) to (312,320).                         */
  616. /*.............................................................*/
  617.     n = (j-294)*40;
  618.     for(i=0;i<width-1;i++)
  619.         {
  620.                 if((j >= 88) && (j <= 304))
  621.                     if((i >= 273) && (i <= 312))
  622.                         {
  623.                             boost = 75.0*taps[i-273];
  624.                             red = rgb_1[3*i+2] + boost;
  625.                             grn = rgb_1[3*i+1] + boost;
  626.                             rgb_1[3*i+2] = min(red,255);
  627.                             rgb_1[3*i+1] = min(grn,255);
  628.                         }
  629.  
  630. /*....          Cap the beam with half of an ellipse.       ...*/
  631.             if((j >= 305) && (j <= 315))
  632.                 if((i >= 273) && (i <= 312))
  633.                     {
  634.                         boost = (75.0*taps[i-273]*image[n])/255.0;
  635.                         red = rgb_1[3*i+2] + boost;
  636.                         grn = rgb_1[3*i+1] + boost;
  637.                         rgb_1[3*i+2] = min(red,255);
  638.                         rgb_1[3*i+1] = min(grn,255);
  639.                         n++;
  640.                     }
  641.         }
  642.     get_dithered_row(width,j,rgb_1,array);
  643.     vsa_raster_line(0,width-1,j,array);
  644.     return;
  645. }                         /*.... END add_beam             .....*/
  646.  
  647.  
  648. /*....................... READ_TGA_HEADER  ....... 5-17-94 ....*/
  649. /* This routine parses through a TGA header and returns the    */
  650. /* file offset in bytes to the first byte of pixel data.       */
  651. /* It also returns image width, height, and type (type 2 is the*/
  652. /* uncompressed 24 bit image type).                            */
  653. /*.............................................................*/
  654. long read_tga_header(int handle, int *width,
  655.                                          int *height, int *type,
  656.                                          int *orientation)
  657. {
  658.     unsigned long offset;
  659.     unsigned char buff[18];
  660.     if(read(handle,buff,18) != 18)
  661.         return -1;
  662.     offset = 18+buff[0];
  663.     *type = buff[2];
  664.  
  665.     *width  = *((unsigned *)buff + 6);
  666.     *height = *((unsigned *)buff + 7);
  667.     *orientation = buff[17];
  668.     return offset;
  669. }                           /*.... END read_tga_header    .....*/
  670.  
  671.  
  672. /*....................... WRITE_TGA_HEADER  ....... 7-5-94 ....*/
  673. /* This routine writes a TGA header: 24 bit true color image   */
  674. /*.............................................................*/
  675. int write_tga_header(int handle, int width,int height,
  676.                                             int orientation)
  677. {
  678.     int error = 0;
  679.     unsigned char buff[18];
  680.     buff[0] = 0;
  681.     buff[1] = 0;
  682.     buff[2] = 2;
  683.     buff[3] = 0;
  684.     buff[4] = 0;
  685.     buff[5] = 0;
  686.     buff[6] = 0;
  687.     buff[7] = 0;
  688.     buff[8] = 0;
  689.     *((unsigned *)buff + 4) = 0;
  690.     *((unsigned *)buff + 5) = 0;
  691.     *((unsigned *)buff + 6) = width;
  692.     *((unsigned *)buff + 7) = height;
  693.     buff[16] = 24;
  694.     buff[17] = orientation;
  695.     if(write(handle,buff,18) != 18)
  696.         error = -1;
  697.     return error;
  698. }                           /*.... END write_tga_header   .....* /
  699.  
  700.  
  701. /*.................... GET_DITHERED_ROW ......... 7-15-94 .....*/
  702. /* This routine computes the dithered pixel color for all of   */
  703. /* pixels in a row in the array 'rgb' and stores the results   */
  704. /* in the array 'pixels'. The row is 'width' wide and starts at*/
  705. /* screen row address 'j'.  The 'rgb' array is a 24 bit color  */
  706. /* array with every 3 bytes defining a new pixel.  The         */
  707. /* resulting 'pixels' array defines each pixel as an 8 bit RGB */
  708. /* pixel (one byte per pixel).                                 */
  709. /*.............................................................*/
  710. void get_dithered_row(int width,int j,unsigned char *rgb,
  711.                                              unsigned char *pixels)
  712. {
  713.     int i,n,m,q,r,red_lvl,grn_lvl,blu_lvl,size,size_sqr;
  714.     int red_boost,grn_boost,blu_boost;
  715.     float x,y,frl,fgl,fbl;
  716.     size = 8;
  717.     size_sqr = 64;
  718.     q = 3;
  719. /*.... If FAST_RGB = 1, don't dither, do fast 8 bit RGB.    ....*/
  720.     if(FAST_RGB)
  721.         {
  722.             for(i=0;i<width;i++)
  723.                 {
  724.                     pixels[i] = (rgb[3*i+2] & 0xe0) +
  725.                                             ((rgb[3*i+1] & 0xe0) >> 3) +
  726.                                             (rgb[3*i+0] >> 6);
  727.                 }
  728.             return;
  729.         }
  730.     y = (float)j/size;
  731.     n = (int)(size*(y - (int)y) + 0.5);
  732.     for(i=0;i<width;i++)
  733.         {
  734. /*.............................................................*/
  735. /* For the pixels screen address i,j, compute pixel address r  */
  736. /* within the dither box.  Also select dither box q based on   */
  737. /* size (size = 1, 2, 4, or 8) (q = 0, 1, 2, or 3).            */
  738. /*.............................................................*/
  739.             x = (float)i/size;
  740.             m = (int)(size*(x - (int)x) + 0.5);
  741.             r = m+n*size;
  742. /*.............................................................*/
  743. /* Get the Dark Pixel color, the Light Pixel components, and   */
  744. /* the pixel color errors.                                     */
  745. /*.............................................................*/
  746.             pixels[i] = crack_rgb(rgb+3*i,&red_boost,&grn_boost,
  747.                                                         &blu_boost,&frl,&fgl,&fbl);
  748. /*.............................................................*/
  749. /*Scale the pixel color error values based on dither box size  */
  750. /*.............................................................*/
  751.             red_lvl = size_sqr*frl;
  752.             grn_lvl = size_sqr*fgl;
  753.             blu_lvl = size_sqr*fbl;
  754. /*.............................................................*/
  755. /*Test the pixels red, green, and blue error values against the*/
  756. /*thresholds in the dither box.  Decide which color to use.    */
  757. /*.............................................................*/
  758.             if(dither[q][r] <= red_lvl)                   /*Boost Red*/
  759.                 pixels[i] = (pixels[i] & 0x1f)+(red_boost<<5);
  760.             if(dither[q][r] <= grn_lvl)                   /*Boost Grn*/
  761.                 pixels[i] = (pixels[i] & 0xe3)+(grn_boost<<2);
  762.             if(dither[q][r] <= blu_lvl)                   /*Boost Blu*/
  763.                 pixels[i] = (pixels[i] & 0xfc)+blu_boost;
  764.         }
  765.     return;
  766. }                           /*.... END get_dithered_row    ....*/
  767.  
  768.  
  769.  
  770. /*.......................... CRACK_RGB ........... 5-27-94 ....*/
  771. /* This routine takes the 24 bit RGB color value in the 'rgb'  */
  772. /* array, quantizes it down to an 8 bit color value (3 bit red,*/
  773. /* 3 bit green, and 2 bit blue) and returns this 8 bit         */
  774. /* 'base_color' value. It also computes the 8 bit color boost  */
  775. /* values '*red_boost', 'grn_boost', and 'blu_boost' which are */
  776. /* used to draw dithered pixels.  It also computes the color   */
  777. /* error values 'red_lvl', 'grn_lvl', and 'blu_lvl' which      */
  778. /* determine when the dither function draws with 'base_color'  */
  779. /* and when it draws with 'xxx_boost' color.                   */
  780. /*.............................................................*/
  781. int crack_rgb(unsigned char *rgb,int *red_boost,int *grn_boost,
  782.                             int *blu_boost,float *red_lvl,float *grn_lvl,
  783.                             float *blu_lvl)
  784. {
  785.     int   base_color,red,grn,blu;
  786.     float fred,fgrn,fblu;
  787.  
  788.     fred = rgb[2]/36.6;   /*36.6 = (256 shades of red)/(2^3 - 1) */
  789.     fgrn = rgb[1]/36.6;   /*36.6 = (256 shades of grn)/(2^3 - 1) */
  790.     fblu = rgb[0]/85.4;   /*85.4 = (256 shades of blu)/(2^2 - 1) */
  791.  
  792.     red = fred;
  793.     grn = fgrn;
  794.     blu = fblu;
  795.     base_color = (red << 5)+(grn << 2)+blu;   /*Dark Pixel color */
  796.  
  797.     *red_lvl = fred - red;
  798.     *grn_lvl = fgrn - grn;
  799.     *blu_lvl = fblu - blu;
  800.  
  801.     *red_boost = red+1;  /*This is the Light Pixel color for red */
  802.     *grn_boost = grn+1;  /*This is the Light Pixel color for grn */
  803.     *blu_boost = blu+1;  /*This is the Light Pixel color for blu */
  804.  
  805.     return base_color;
  806. }                           /*.... END crack_rgb          .....*/
  807.  
  808.  
  809. /*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
  810. /* This routine generates a 'true color' LUT.  An 8 bit index  */
  811. /* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
  812. /* 2 bits of BLUE.  The 3 msbs of the 8 bit index are the RED  */
  813. /* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
  814. /*                                                             */
  815. /*.............................................................*/
  816. void true_color_lut(void)
  817. {
  818.     int i;
  819.     unsigned char color_array[768];
  820.     for(i=0;i<256;i++)
  821.         {
  822.             color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
  823.             color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
  824.             color_array[3*i+2]= (i & 0x0003) * 21;
  825.         }
  826.     vsa_write_color_block(0,256,color_array);
  827.     return;
  828. }                          /*.....   End true_color_lut   .....*/
  829.  
  830.  
  831. /*.................... COLOR_MAG .............. 7-15-94 .......*/
  832. /* This routine takes an RGB color defined by 'r', 'g', and    */
  833. /* 'b' and returns the absolute magnitude (brightness) of the  */
  834. /* color.                                                      */
  835. /*.............................................................*/
  836. float color_mag(float r,float g,float b)
  837. {
  838.     return sqrt(r*r+g*g+b*b);
  839. }                          /*.....   End color_mag        .....*/
  840.  
  841.  
  842. /*.................... COLOR_ERROR ............ 7-15-94 .......*/
  843. /* This routine takes two RGB colors defined by 'r0', 'g0',    */
  844. /* 'b0' and 'r1', 'g1', 'b1' and returns the distance between  */
  845. /* the two colors in RGB color space.                          */
  846. /*.............................................................*/
  847. float color_error(float r0,float g0,float b0,
  848.                                     float r1,float g1,float b1)
  849. {
  850.     float dr,dg,db;
  851.     dr = (r0-r1);
  852.     dg = (g0-g1);
  853.     db = (b0-b1);
  854.     return sqrt(dr*dr+dg*dg+db*db);
  855. }                          /*.....   End color_error      .....*/
  856.  
  857.  
  858. /*.................... HUE_ERROR .............. 7-15-94 .......*/
  859. /* This routine compares the RGB color defined by 'r,g,b' to   */
  860. /* the color HUE defined by 'ur,ug,ub' and returns the distance*/
  861. /* between the RGB color and the HUE.  The distance ranges     */
  862. /* from 0 to square root of 3 (1.73...)                        */
  863. /* NOTE: 'ur,ug,ub' is a "Unit Vector" and                     */
  864. /*       sqrt(ur*ur + ug*ug + ub*ub) must equal 1.0.           */
  865. /*.............................................................*/
  866. float hue_error(float r,float g,float b,
  867.                                 float ur,float ug,float ub)
  868. {
  869.     float dr,dg,db,mag;
  870.     mag = color_mag(r,g,b);
  871.     if(mag == 0) mag = 1.0;
  872.     dr = (r/mag-ur);
  873.     dg = (g/mag-ug);
  874.     db = (b/mag-ub);
  875.     return sqrt(dr*dr+dg*dg+db*db);
  876. }                          /*.....   End hue_error        .....*/
  877.  
  878.  
  879. /*.......................... BUMMER ...........................*/
  880. /* This routine prints a file error message.  You give         */
  881. /* it the name of the file for the message in 'filename'.      */
  882. /*.............................................................*/
  883. void bummer(char *filename)
  884. {
  885.     char text[100];
  886.     sprintf(text,
  887.     "File Access Error!  Filename = '%s'",filename);
  888.     vsa_write_string(0,YResolution-2*YCharSize,224,text);
  889.     vsa_write_string(0,YResolution-1*YCharSize,224,
  890.                                      "Hit Any Key ...");
  891.     getch();
  892.     vsa_init(3);
  893.     exit(1);
  894. }                          /*.....   End bummer           .....*/
  895.  
  896.  
  897. /*......................... TEXT_UPDATE .......................*/
  898. /* This routine prints the text string in 'text' out to the    */
  899. /* screen in 'color'.  It does this at the bottom center of a  */
  900. /* 640 x 480 screen by first clearing out the last printed     */
  901. /* message.                                                    */
  902. /*.............................................................*/
  903. void  text_update(char *text,int color)
  904. {
  905.     vsa_set_text_scale(1.2,1.2);
  906.     vsa_set_color(0);
  907.     vsa_move_to(200,475-YCharSize-1);
  908.     vsa_rect_fill(460,475);
  909.     vsa_write_string(205,475-YCharSize,color,text);
  910.     return;
  911. }                          /*.....   End text_update      .....*/
  912.  
  913.  
  914. /*............................. FRAME .........................*/
  915. /* This routine draws a frame around the 640 x 480 screen.     */
  916. /* The reason I do this is so that you can tell when an image  */
  917. /* is being redrawn (the frame slowly gets eaten up).          */
  918. /*.............................................................*/
  919. void  frame(void)
  920. {
  921.     vsa_set_color(255);
  922.     vsa_move_to(0,0);
  923.     vsa_rect(639,479);
  924.     vsa_set_color(0);
  925.     vsa_move_to(1,1);
  926.     vsa_rect(638,478);
  927.     vsa_set_color(255);
  928.     vsa_move_to(2,2);
  929.     vsa_rect(637,477);
  930.     vsa_set_color(0);
  931.     vsa_move_to(3,3);
  932.     vsa_rect(636,476);
  933.     return;
  934. }                          /*.....   End frame            .....*/
  935.  
  936.  
  937. /*......................... ELLIPSE .............. 7-22-94 ....*/
  938. /* This routine generates a filled ellipse mask into the       */
  939. /* global 'image array.  The ellipse has width of 'dx' and     */
  940. /* height of 'dy'.  The equation for this ellipse is:          */
  941. /*                                                             */
  942. /*                    x^2    +     y^2                         */
  943. /*                 --------     --------   =  1                */
  944. /*                 (dx/2)^2     (dy/2)^2                       */
  945. /*                                                             */
  946. /* The 'image' array values are 0 outside of the ellipse and   */
  947. /* 255 inside the ellipse. The ellipse has a soft edge with    */
  948. /* 'image' values between 0 and 255.  The soft edge is         */
  949. /* achieved by a 3x3 pixel averaging operation via the         */
  950. /* 'soft_edge' function.                                       */
  951. /*                                                             */
  952. /* NOTE: The 'image' array must be large enough to hold all of */
  953. /*       this data (image will be dx wide and dy high).        */
  954. /*.............................................................*/
  955. void ellipse(int dx,int dy)
  956. {
  957.     int i,j,m,n;
  958.     float rx,ry;
  959. /*.............................................................*/
  960. /*   Clear out the image array before writing in ellipse mask. */
  961. /*.............................................................*/
  962.     for(n=0;n<dy;n++)
  963.         for(m=0;m<dx;m++)
  964.             image[m+n*dx] = 0;
  965. /*.............................................................*/
  966. /*   Now compute ellipse and draw its mask into image array.   */
  967. /*.............................................................*/
  968.     rx = (dx-1)/2.0;
  969.     ry = (dy-1)/2.0;
  970.     for(j=-ry ; j<=+ry ; j++)
  971.         {
  972.             i = sqrt(rx*rx*(1 - (j*j)/(ry*ry)));
  973.             for(m=-i;m<=i;m++)
  974.                 {
  975.                     n = m+rx+(j+(int)ry)*dx;
  976.                     image[n] = 255;
  977.                 }
  978.         }
  979.     soft_edge(image,dx,dy);
  980.     return;
  981. }                          /*.....   End ellipse          .....*/
  982.  
  983.  
  984. void introduction(void)
  985. {
  986.     printf("This program goes through the evolution of mild\n");
  987.     printf("mannered MOUNTAIN.TGA to the ultimate UFO sighting\n");
  988.     printf("UFO.TGA.  Before you run this program, You must\n");
  989.     printf("have the following three files in the current\n");
  990.     printf("directory:\n");
  991.     printf("              MOUNTAIN.TGA\n");
  992.     printf("              CITY.TGA\n");
  993.     printf("              SAUCER.TGA\n");
  994.     printf("\n");
  995.     printf("Furthermore, you need an additional 7 Mbytes\n");
  996.     printf("of hard disk space available since the following\n");
  997.     printf("intermediate TARGA image files are created:\n");
  998.     printf("\n");
  999.     printf("              SKY.TGA\n");
  1000.     printf("              WIPED.TGA\n");
  1001.     printf("              WITHCITY.TGA\n");
  1002.     printf("              WITHSKY.TGA\n");
  1003.     printf("              WITHSAUC.TGA\n");
  1004.     printf("              WITHSHAD.TGA\n");
  1005.     printf("              UFO.TGA  (This is the final image)\n");
  1006.     printf("\n");
  1007.     printf("Hit any key to continue, ESC to quit.\n");
  1008.     if(getch() == 27)
  1009.         exit(1);
  1010.     return;
  1011. }
  1012.  
  1013. void soft_edge(unsigned char *image,int width,int height)
  1014. {
  1015.     int i,j,m,n,q,x,y;
  1016. /*.............................................................*/
  1017. /*   First clear out the temporary array.                      */
  1018. /*.............................................................*/
  1019.     for(i=0;i<width*height;i++)
  1020.         big_image[i] = 0;
  1021. /*.............................................................*/
  1022. /*   Now, for each pixel in 'image' array, do a 3x3 pixel      */
  1023. /*   average.                                                  */
  1024. /*.............................................................*/
  1025.     for(j=0;j<height;j++)
  1026.         for(i=0;i<width;i++)
  1027.             {
  1028.                 q = i+j*width;
  1029.                 for(n=0;n<3;n++)
  1030.                     for(m=0;m<3;m++)
  1031.                         {
  1032.                             x = i+m-1;
  1033.                             y = j+n-1;
  1034.                             if((y >= 0) && (y < height))
  1035.                                 if((x >= 0) && (x < width))
  1036.                                     big_image[q] += image[x+y*width];
  1037.                         }
  1038.                 big_image[q] = big_image[q]/9;
  1039.             }
  1040. /*.............................................................*/
  1041. /*     Finally, transfer results back to the 'image' array.    */
  1042. /*.............................................................*/
  1043.     for(i=0;i<width*height;i++)
  1044.         image[i] = big_image[i];
  1045.     return;
  1046. }
  1047.